﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using JobsBoardDAL.DTOs;

namespace JobsBoardDAL
{
    public class JobsBoardCRUD
    {
        private static void SaveContext(JobsBoardDatabaseEntities context)
        {
            try
            {
                context.SaveChanges();
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());

                throw e;
            }
        }

        private static void ThrowNotFoundException(string objectName, string parameter)
        {
            throw new ArgumentException(String.Format("{0} Not found by parameter: {1}", objectName, parameter));
        }

        #region Industries

        public static IndustryDTO GetIndustryByID(int id)
        {
            IndustryDTO industryDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Industry industry = context.Industries.FirstOrDefault(i => i.IndustryID == id);

                if (industry != null)
                {
                    industryDTO = new IndustryDTO() { IndustryName = industry.IndustryName, ID = industry.IndustryID };
                }
                else
                {
                    ThrowNotFoundException("Industry", id.ToString());
                }
            }

            return industryDTO;
        }

        public static IndustryDTO GetIndustryByName(string name)
        {
            IndustryDTO industryDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Industry industry = context.Industries.FirstOrDefault(i => i.IndustryName == name);

                if (industry != null)
                {
                    industryDTO = new IndustryDTO() { IndustryName = industry.IndustryName, ID = industry.IndustryID };
                }
                else
                {
                    ThrowNotFoundException("Industry", name);
                }
            }

            return industryDTO;
        }

        public static void AddIndustry(IndustryDTO industryDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                context.Industries.AddObject(industryDTO.ToIndustry());
                SaveContext(context);
            }
        }

        public static void DeleteIndustry(IndustryDTO industryDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Industry industry = context.Industries.FirstOrDefault(i => i.IndustryName == industryDTO.IndustryName);

                if (industry != null)
                {
                    context.Industries.DeleteObject(industry);
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Industry", industryDTO.IndustryName);
                }
            }
        }

        public static void EditIndustry(IndustryDTO industryDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Industry industry = context.Industries.FirstOrDefault(i => i.IndustryID == industryDTO.ID);

                if (industry != null)
                {
                    industry.IndustryName = industryDTO.IndustryName;
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Industry", industryDTO.IndustryName);
                }
            }
        }

        public static IEnumerable<IndustryDTO> GetIndustries()
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var industries = context.Industries
                                        .Select(x => new IndustryDTO() { IndustryName = x.IndustryName, ID = x.IndustryID })
                                        .ToList();

                return industries;
            }
        }
        #endregion

        #region Statuses
        public static StatusDTO GetStatusByID(int id)
        {
            StatusDTO industryDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Status industry = context.Statuses.FirstOrDefault(i => i.StatusID == id);

                if (industry != null)
                {
                    industryDTO = new StatusDTO() { StatusName = industry.StatusName, ID = industry.StatusID };
                }
                else
                {
                    ThrowNotFoundException("Status", id.ToString());
                }
            }

            return industryDTO;
        }

        public static StatusDTO GetStatusByName(string name)
        {
            StatusDTO statusDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Status industry = context.Statuses.FirstOrDefault(i => i.StatusName == name);

                if (industry != null)
                {
                    statusDTO = new StatusDTO() { StatusName = industry.StatusName, ID = industry.StatusID };
                }
                else
                {
                    ThrowNotFoundException("Status", name);
                }
            }

            return statusDTO;
        }

        public static void AddStatus(StatusDTO statusDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                context.Statuses.AddObject(statusDTO.ToStatus());
                SaveContext(context);
            }
        }

        public static void DeleteStatus(StatusDTO statusDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Status status = context.Statuses.FirstOrDefault(i => i.StatusName == statusDTO.StatusName);

                if (status != null)
                {
                    context.Statuses.DeleteObject(status);
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Status", statusDTO.StatusName);
                }
            }
        }

        public static void EditStatus(StatusDTO statusDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Status status = context.Statuses.FirstOrDefault(i => i.StatusID == statusDTO.ID);

                if (status != null)
                {
                    status.StatusName = statusDTO.StatusName;
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Status", statusDTO.StatusName);
                }
            }
        }

        public static IEnumerable<StatusDTO> GetStatuses()
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var statuses = context.Statuses
                                      .Select(x => new StatusDTO() { StatusName = x.StatusName, ID = x.StatusID })
                                      .ToList();

                return statuses;
            }
        }
            
        #endregion

        #region Companies

        public static CompanyDTO GetCompanyByID(int id)
        {
            CompanyDTO companyDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Company company = context.Companies.FirstOrDefault(i => i.CompanyID == id);

                if (company != null)
                {
                    companyDTO = new CompanyDTO();
                    companyDTO.FillFromCompany(company);
                }
                else
                {
                    ThrowNotFoundException("Industry", id.ToString());
                }
            }

            return companyDTO;
        }

        public static CompanyDTO GetCompanyByName(string name)
        {
            CompanyDTO companyDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Company company = context.Companies.FirstOrDefault(i => i.CompanyName == name);

                if (company != null)
                {
                    companyDTO = new CompanyDTO();
                    companyDTO.FillFromCompany(company);
                }
                else
                {
                    ThrowNotFoundException("Industry", name.ToString());
                }
            }

            return companyDTO;
        }

        public static void AddCompany(CompanyDTO companyDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                context.Companies.AddObject(companyDTO.ToCompany());
                SaveContext(context);
            }
        }

        public static void DeleteCompany(CompanyDTO companyDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Company company = context.Companies.FirstOrDefault(i => i.CompanyName == companyDTO.CompanyName);

                if (company != null)
                {
                    context.Companies.DeleteObject(company);
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Industry", companyDTO.CompanyName);
                }
            }
        }

        public static void EditCompany(CompanyDTO companyDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Company company = context.Companies.FirstOrDefault(i => i.CompanyID == companyDTO.ID);

                if (company != null)
                {
                    company.CompanyName = companyDTO.CompanyName;
                    company.CompanyLogo = companyDTO.Logo;
                    company.Description = companyDTO.Description;
                    company.WebSite = companyDTO.WebSite;
                    company.Email = companyDTO.Email;
                    company.Phone = companyDTO.Phone;
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Industry", companyDTO.CompanyName);
                }
            }
        }

        public static IEnumerable<CompanyDTO> GetCompanies()
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var companies = context.Companies.ToList();
                List<CompanyDTO> companyDTOs = new List<CompanyDTO>();
                foreach (Company company in companies)
                {
                    CompanyDTO companyDTO = new CompanyDTO();
                    companyDTO.FillFromCompany(company);
                    companyDTOs.Add(companyDTO);
                }

                return companyDTOs;
            }
        }

        #endregion

        #region JobOffers

        public static JobOfferDTO GetJobOfferById(int id)
        {
            JobOfferDTO jobOfferDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                JobOffer jobOffer = context.JobOffers.FirstOrDefault(j => j.JobOfferID == id);

                if (jobOffer != null)
                {
                    jobOfferDTO = CreateJobOfferDTO(jobOffer);
                }
                else
                {
                    ThrowNotFoundException("Offer", id.ToString());
                }
            }

            return jobOfferDTO;
        }
  
        private static JobOfferDTO CreateJobOfferDTO(JobOffer jobOffer)
        {
            JobOfferDTO jobOfferDTO = new JobOfferDTO()
            {
                ID = jobOffer.JobOfferID,
                Status = new StatusDTO() { StatusName = jobOffer.Status.StatusName },
                PublishTime = jobOffer.PublishDate,
                ValidityDays = jobOffer.DaysOfValidity,
                Industry = new IndustryDTO() { IndustryName = jobOffer.Industry.IndustryName },
                JobTitle = jobOffer.JobTitle,
                JobDescription = jobOffer.JobDescription,
            };

            CompanyDTO company = new CompanyDTO();
            company.FillFromCompany(jobOffer.Company);
            jobOfferDTO.Company = company;
            LocationDTO location = new LocationDTO()
            {
                Country = GetCountryByName(jobOffer.Location.Country.CountryName),
                Town = GetCityByName(jobOffer.Location.City.CityName)
            };
            jobOfferDTO.Location = location;

            return jobOfferDTO;
        }

        public static IEnumerable<JobOfferDTO> GetJobOffersByIndustry(IndustryDTO industry)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var jobOffers = context.JobOffers
                                       .Include("Company")
                                       .Include("Industry")
                                       .Include("Location")
                                       .Include("Status")
                                       .Where(j => j.Industry.IndustryName == industry.IndustryName);
                List<JobOfferDTO> jobOfferDTOs = new List<JobOfferDTO>();
                foreach (JobOffer jobOffer in jobOffers)
                {
                    JobOfferDTO jobOfferDTO = new JobOfferDTO();
                    jobOfferDTO = CreateJobOfferDTO(jobOffer);

                    jobOfferDTOs.Add(jobOfferDTO);
                }

                return jobOfferDTOs;
            }
        }

        public static IEnumerable<JobOfferDTO> GetAllOffers()
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var jobOffers = context.JobOffers
                                       .Include("Company")
                                       .Include("Industry")
                                       .Include("Location")
                                       .Include("Status");
                List<JobOfferDTO> jobOfferDTOs = new List<JobOfferDTO>();
                foreach (JobOffer jobOffer in jobOffers)
                {
                    JobOfferDTO jobOfferDTO = new JobOfferDTO();
                    jobOfferDTO = CreateJobOfferDTO(jobOffer);

                    jobOfferDTOs.Add(jobOfferDTO);
                }

                return jobOfferDTOs;
            }
        }

        public static void DeleteOffer(JobOfferDTO jobOfferDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                JobOffer offer = context.JobOffers.FirstOrDefault(j => j.JobOfferID == jobOfferDTO.ID);

                if (offer != null)
                {
                    context.JobOffers.DeleteObject(offer);
                    SaveContext(context);
                }
            }
        }

        public static void EditOffer(JobOfferDTO jobOfferDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                JobOffer offer = context.JobOffers.FirstOrDefault(j => j.JobOfferID == jobOfferDTO.ID);

                if (offer != null)
                {
                    offer.JobDescription = jobOfferDTO.JobDescription;
                    offer.JobTitle = jobOfferDTO.JobTitle;
                    offer.PublishDate = DateTime.Now;
                    Status status = context.Statuses.FirstOrDefault(s => s.StatusName == jobOfferDTO.Status.StatusName);
                    context.Attach(status);
                    offer.Status = status;
                    Industry industry = context.Industries.FirstOrDefault(i => i.IndustryName == jobOfferDTO.Industry.IndustryName);
                    context.Attach(industry);
                    offer.Industry = industry;
                    Company company = context.Companies.FirstOrDefault(c => c.CompanyName == jobOfferDTO.Company.CompanyName);
                    context.Attach(company);
                    offer.Company = company;
                    Location location = context.Locations.FirstOrDefault(l => l.City.CityName == jobOfferDTO.Location.Town.CityName &&
                                                                              l.Country.CountryName == jobOfferDTO.Location.Country.CountryName);
                    if (location == null)
                    {
                        AddCity(jobOfferDTO.Location.Town, jobOfferDTO.Location.Country.CountryName);
                        location = context.Locations.FirstOrDefault(l => l.City.CityName == jobOfferDTO.Location.Town.CityName &&
                                                                              l.Country.CountryName == jobOfferDTO.Location.Country.CountryName);
                    }
                    context.Attach(location);
                    offer.Location = location;

                    SaveContext(context);
                }
            }
        }

        public static void AddOffer(JobOfferDTO jobOfferDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                JobOffer offer = new JobOffer();

                offer.JobDescription = jobOfferDTO.JobDescription;
                offer.JobTitle = jobOfferDTO.JobTitle;
                offer.PublishDate = DateTime.Now;
                Status status = context.Statuses.FirstOrDefault(s => s.StatusName == jobOfferDTO.Status.StatusName);
                context.Attach(status);
                offer.Status = status;
                Industry industry = context.Industries.FirstOrDefault(i => i.IndustryName == jobOfferDTO.Industry.IndustryName);
                context.Attach(industry);
                offer.Industry = industry;
                Company company = context.Companies.FirstOrDefault(c => c.CompanyName == jobOfferDTO.Company.CompanyName);
                context.Attach(company);
                offer.Company = company;
                Location location = context.Locations.FirstOrDefault(l => l.City.CityName == jobOfferDTO.Location.Town.CityName &&
                                                                          l.Country.CountryName == jobOfferDTO.Location.Country.CountryName);
                if (location == null)
                {
                    AddCity(jobOfferDTO.Location.Town, jobOfferDTO.Location.Country.CountryName);
                    location = context.Locations.FirstOrDefault(l => l.City.CityName == jobOfferDTO.Location.Town.CityName &&
                                                                          l.Country.CountryName == jobOfferDTO.Location.Country.CountryName);
                }
                context.Attach(location);
                offer.Location = location;

                context.JobOffers.AddObject(offer);

                SaveContext(context);
            }
        }

        #endregion

        #region Countries

        public static CountryDTO GetCountryByID(int id)
        {
            CountryDTO countryDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Country country = context.Countries.FirstOrDefault(i => i.CountryID == id);

                if (country != null)
                {
                    countryDTO = new CountryDTO() { CountryName = country.CountryName, ID = country.CountryID };
                }
                else
                {
                    ThrowNotFoundException("Country", id.ToString());
                }
            }

            return countryDTO;
        }

        public static CountryDTO GetCountryByName(string name)
        {
            CountryDTO countryDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                Country country = context.Countries.FirstOrDefault(i => i.CountryName == name);

                if (country != null)
                {
                    countryDTO = new CountryDTO() { CountryName = country.CountryName, ID = country.CountryID };
                }
                else
                {
                    ThrowNotFoundException("Country", name);
                }
            }

            return countryDTO;
        }

        public static void AddCountry(CountryDTO countryDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                context.Countries.AddObject(countryDTO.ToCountry());
                SaveContext(context);
            }
        }

        public static void DeleteCountry(CountryDTO countryDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Country country = context.Countries.FirstOrDefault(i => i.CountryName == countryDTO.CountryName);

                if (country != null)
                {
                    context.Countries.DeleteObject(country);
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Country", countryDTO.CountryName);
                }
            }
        }

        public static void EditCountry(CountryDTO countryDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                Country country = context.Countries.FirstOrDefault(i => i.CountryID == countryDTO.ID);

                if (country != null)
                {
                    country.CountryName = countryDTO.CountryName;
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Country", countryDTO.CountryName);
                }
            }
        }

        public static IEnumerable<CountryDTO> GetCountries()
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var countries = context.Countries
                                       .Select(x => new CountryDTO() { CountryName = x.CountryName, ID = x.CountryID })
                                       .ToList();

                return countries;
            }
        }

        #endregion  

        #region Cities

        public static CityDTO GetCityByID(int id)
        {
            CityDTO cityDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                City city = context.Cities.FirstOrDefault(i => i.CityID == id);

                if (city != null)
                {
                    cityDTO = new CityDTO() { CityName = city.CityName, ID = city.CityID };
                }
                else
                {
                    ThrowNotFoundException("City", id.ToString());
                }
            }

            return cityDTO;
        }

        public static CityDTO GetCityByName(string name)
        {
            CityDTO cityDTO = null;

            using (var context = new JobsBoardDatabaseEntities())
            {
                City city = context.Cities.FirstOrDefault(i => i.CityName == name);

                if (city != null)
                {
                    cityDTO = new CityDTO() { CityName = city.CityName, ID = city.CityID };
                }
                else
                {
                    ThrowNotFoundException("City", name);
                }
            }

            return cityDTO;
        }

        public static void AddCity(CityDTO cityDTO, string countryName)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                try
                {
                    context.Cities.AddObject(cityDTO.ToCity());
                }
                catch
                {
                }
                SaveContext(context);

                Country country = context.Countries.FirstOrDefault(c => c.CountryName == countryName);
                City city = context.Cities.FirstOrDefault(c => c.CityName == cityDTO.CityName);

                Location location = new Location()
                {
                    City = city,
                    Country = country,
                };

                context.Locations.AddObject(location);
                SaveContext(context);
            }
        }

        public static void DeleteCity(CityDTO cityDTo)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                City city = context.Cities.FirstOrDefault(i => i.CityName == cityDTo.CityName);
                var locations = context.Locations.Where(l => l.City.CityName == cityDTo.CityName);

                if (city != null)
                {
                    foreach (Location l in locations)
                    {
                        context.Locations.DeleteObject(l);
                    }

                    context.Cities.DeleteObject(city);
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("Country", cityDTo.CityName);
                }
            }
        }

        public static void EditCity(CityDTO cityDTO)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                City city = context.Cities.FirstOrDefault(i => i.CityID == cityDTO.ID);

                if (city != null)
                {
                    city.CityName = cityDTO.CityName;
                    SaveContext(context);
                }
                else
                {
                    ThrowNotFoundException("City", cityDTO.CityName);
                }
            }
        }

        public static IEnumerable<CityDTO> GetCities()
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var cities = context.Cities
                                    .Select(x => new CityDTO() { CityName = x.CityName, ID = x.CityID })
                                    .ToList();

                return cities;
            }
        }

        public static IEnumerable<CityDTO> GetCitiesByCountry(CountryDTO country)
        {
            using (var context = new JobsBoardDatabaseEntities())
            {
                var cities = context.Locations
                                    .Where(x => x.Country.CountryName == country.CountryName)
                                    .Select(x => new CityDTO() { CityName = x.City.CityName, ID = x.City.CityID })
                                    .ToList();

                return cities;
            }
        }
        #endregion  
    }
}